import java.io.*;

public class SharedObject implements Serializable, SharedObject_itf {

    private int lock; // état du lock
    private int id; // id sera alloué par le système a la création de l'objet
    Object obj; // référence à l'objet

    public SharedObject(int id, Object obj) {
        this.lock = EtatLock.NL;
        this.id = id;
        this.obj = obj;
    }

    // invoked by the user program on the client node
    public void lock_read() {
        switch (this.lock) {
        case EtatLock.NL:
            this.lock = EtatLock.RLT;
            break;
        case EtatLock.WLC:
            this.lock = EtatLock.RLT_WLC;
            break;
        case EtatLock.RLC:
            this.lock = EtatLock.RLT;
            break;
        }
        this.lock = EtatLock.RLT;
    }

    // invoked by the user program on the client node
    public void lock_write() {
        switch (this.lock) {
        case EtatLock.NL:
            this.lock = EtatLock.WLT;
            break;
        case EtatLock.RLC:
            this.lock = EtatLock.WLT;
            break;
        case EtatLock.WLC:
            this.lock = EtatLock.WLT;
            break;
        }
        this.lock = EtatLock.WLT;
    }

    // invoked by the user program on the client node
    public synchronized void unlock() {

        switch (this.lock) {
        case EtatLock.RLT:
            this.lock = EtatLock.RLC;
            break;
        case EtatLock.WLT:
            this.lock = EtatLock.WLC;
            break;
        case EtatLock.RLT_WLC:
            this.lock = EtatLock.WLC;
            break;
        }
        notify();
    }

    /* Appel locaux */

    // callback invoked remotely by the server
    public synchronized Object reduce_lock() {
        if (this.lock == EtatLock.RLT || this.lock == EtatLock.WLT
                || this.lock == EtatLock.RLT_WLC) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (this.lock == EtatLock.WLC)
            this.lock = EtatLock.RLC;
        notify();
        return this;
    }

    // callback invoked remotely by the server
    public synchronized void invalidate_reader() {
        if (this.lock == EtatLock.RLT || this.lock == EtatLock.WLT
                || this.lock == EtatLock.RLT_WLC) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (this.lock == EtatLock.RLC)
            this.lock = EtatLock.NL;
        notify();
    }

    public synchronized Object invalidate_writer() {
        if (this.lock == EtatLock.RLT || this.lock == EtatLock.WLT
                || this.lock == EtatLock.RLT_WLC) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (this.lock == EtatLock.RLT_WLC || this.lock == EtatLock.WLT
                || this.lock == EtatLock.WLC)
            this.lock = EtatLock.NL;
        notify();
        return this;
    }

    @Override
    public int getId() {
        return this.id;
    }
}

